

<!DOCTYPE html>
<html lang="zh-CN" data-default-color-scheme=auto>



<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/img/fluid.png">
  <link rel="icon" href="/img/fluid.png">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="author" content="深海火锅店">
  <meta name="keywords" content="">
  
    <meta name="description" content="Spring原理Spring特点 它是一个全面的、企业应用开发一站式的解决方案，贯穿表现层、业务层、持久层。但是 Spring仍然可以和其他的框架无缝整合。  轻量级控制反转面向切面容器框架集合 Spring核心组件 Spring常用模块 Spring主要包 Spring常用注解 bean 注入与装配的的方式有很多种，可以通过 xml、get set 方式，、造函数或者注解等。简单易用的方式就是使">
<meta property="og:type" content="article">
<meta property="og:title" content="spring原理">
<meta property="og:url" content="http://example.com/2022/12/17/%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/Java/%E5%AD%A6%E4%B9%A0/%E5%9F%BA%E7%A1%80/004_Spring%E5%8E%9F%E7%90%86/index.html">
<meta property="og:site_name" content="Hexo">
<meta property="og:description" content="Spring原理Spring特点 它是一个全面的、企业应用开发一站式的解决方案，贯穿表现层、业务层、持久层。但是 Spring仍然可以和其他的框架无缝整合。  轻量级控制反转面向切面容器框架集合 Spring核心组件 Spring常用模块 Spring主要包 Spring常用注解 bean 注入与装配的的方式有很多种，可以通过 xml、get set 方式，、造函数或者注解等。简单易用的方式就是使">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://gitee.com/tongstyle/blog-img/raw/master/img/202301201942533.png">
<meta property="og:image" content="https://gitee.com/tongstyle/blog-img/raw/master/img/202301201942720.png">
<meta property="og:image" content="https://gitee.com/tongstyle/blog-img/raw/master/img/202301201942329.png">
<meta property="og:image" content="https://gitee.com/tongstyle/blog-img/raw/master/img/202301201942662.png">
<meta property="og:image" content="https://gitee.com/tongstyle/blog-img/raw/master/img/202301201942615.png">
<meta property="og:image" content="https://gitee.com/tongstyle/blog-img/raw/master/img/202301201942195.png">
<meta property="og:image" content="https://gitee.com/tongstyle/blog-img/raw/master/img/202301201942258.png">
<meta property="og:image" content="https://gitee.com/tongstyle/blog-img/raw/master/img/202301201941273.png">
<meta property="og:image" content="https://gitee.com/tongstyle/blog-img/raw/master/img/202301201942455.png">
<meta property="article:published_time" content="2022-12-16T16:00:00.000Z">
<meta property="article:modified_time" content="2024-02-15T16:04:48.994Z">
<meta property="article:author" content="深海火锅店">
<meta property="article:tag" content="java基础">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://gitee.com/tongstyle/blog-img/raw/master/img/202301201942533.png">
  
  
    <meta name="referrer" content="no-referrer-when-downgrade">
  
  
  <title>spring原理 - Hexo</title>

  <link  rel="stylesheet" href="https://lib.baomitu.com/twitter-bootstrap/4.6.1/css/bootstrap.min.css" />



  <link  rel="stylesheet" href="https://lib.baomitu.com/github-markdown-css/4.0.0/github-markdown.min.css" />

  <link  rel="stylesheet" href="https://lib.baomitu.com/hint.css/2.7.0/hint.min.css" />

  <link  rel="stylesheet" href="https://lib.baomitu.com/fancybox/3.5.7/jquery.fancybox.min.css" />



<!-- 主题依赖的图标库，不要自行修改 -->
<!-- Do not modify the link that theme dependent icons -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_hj8rtnfg7um.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_lbnruvf0jn.css">


<link  rel="stylesheet" href="/css/main.css" />


  <link id="highlight-css" rel="stylesheet" href="/css/highlight.css" />
  
    <link id="highlight-css-dark" rel="stylesheet" href="/css/highlight-dark.css" />
  




  <script id="fluid-configs">
    var Fluid = window.Fluid || {};
    Fluid.ctx = Object.assign({}, Fluid.ctx)
    var CONFIG = {"hostname":"example.com","root":"/","version":"1.9.3","typing":{"enable":true,"typeSpeed":70,"cursorChar":"_","loop":false,"scope":[]},"anchorjs":{"enable":true,"element":"h1,h2,h3,h4,h5,h6","placement":"left","visible":"hover","icon":""},"progressbar":{"enable":true,"height_px":3,"color":"#29d","options":{"showSpinner":false,"trickleSpeed":100}},"code_language":{"enable":true,"default":"TEXT"},"copy_btn":true,"image_caption":{"enable":true},"image_zoom":{"enable":true,"img_url_replace":["",""]},"toc":{"enable":true,"placement":"right","headingSelector":"h1,h2,h3,h4,h5,h6","collapseDepth":0},"lazyload":{"enable":true,"loading_img":"/img/loading.gif","onlypost":false,"offset_factor":2},"web_analytics":{"enable":false,"follow_dnt":true,"baidu":null,"google":null,"gtag":null,"tencent":{"sid":null,"cid":null},"woyaola":null,"cnzz":null,"leancloud":{"app_id":null,"app_key":null,"server_url":null,"path":"window.location.pathname","ignore_local":false}},"search_path":"/local-search.xml"};

    if (CONFIG.web_analytics.follow_dnt) {
      var dntVal = navigator.doNotTrack || window.doNotTrack || navigator.msDoNotTrack;
      Fluid.ctx.dnt = dntVal && (dntVal.startsWith('1') || dntVal.startsWith('yes') || dntVal.startsWith('on'));
    }
  </script>
  <script  src="/js/utils.js" ></script>
  <script  src="/js/color-schema.js" ></script>
  


  
<meta name="generator" content="Hexo 6.3.0"></head>


<body>
  

  <header>
    

<div class="header-inner" style="height: 70vh;">
  <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand" href="/">
      <strong>Fluid</strong>
    </a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/">
                <i class="iconfont icon-home-fill"></i>
                首页
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/archives/">
                <i class="iconfont icon-archive-fill"></i>
                归档
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/categories/">
                <i class="iconfont icon-category-fill"></i>
                分类
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/tags/">
                <i class="iconfont icon-tags-fill"></i>
                标签
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/about/">
                <i class="iconfont icon-user-fill"></i>
                关于
              </a>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" target="_self" href="javascript:;" data-toggle="modal" data-target="#modalSearch" aria-label="Search">
              &nbsp;<i class="iconfont icon-search"></i>&nbsp;
            </a>
          </li>
          
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" target="_self" href="javascript:;" aria-label="Color Toggle">&nbsp;<i
                class="iconfont icon-dark" id="color-toggle-icon"></i>&nbsp;</a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

  

<div id="banner" class="banner" parallax=true
     style="background: url('/img/background.jpg') no-repeat center center; background-size: cover;">
  <div class="full-bg-img">
    <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
      <div class="banner-text text-center fade-in-up">
        <div class="h2">
          
            <span id="subtitle" data-typed-text="spring原理"></span>
          
        </div>

        
          
  <div class="mt-3">
    
    
      <span class="post-meta">
        <i class="iconfont icon-date-fill" aria-hidden="true"></i>
        <time datetime="2022-12-17 00:00" pubdate>
          2022年12月17日 凌晨
        </time>
      </span>
    
  </div>

  <div class="mt-1">
    
      <span class="post-meta mr-2">
        <i class="iconfont icon-chart"></i>
        
          14k 字
        
      </span>
    

    
      <span class="post-meta mr-2">
        <i class="iconfont icon-clock-fill"></i>
        
        
        
          118 分钟
        
      </span>
    

    
    
  </div>


        
      </div>

      
    </div>
  </div>
</div>

</div>

  </header>

  <main>
    
      

<div class="container-fluid nopadding-x">
  <div class="row nomargin-x">
    <div class="side-col d-none d-lg-block col-lg-2">
      

    </div>

    <div class="col-lg-8 nopadding-x-md">
      <div class="container nopadding-x-md" id="board-ctn">
        <div id="board">
          <article class="post-content mx-auto">
            <!-- SEO header -->
            <h1 style="display: none">spring原理</h1>
            
            
              <div class="markdown-body">
                
                <h2 id="Spring原理"><a href="#Spring原理" class="headerlink" title="Spring原理"></a>Spring原理</h2><h3 id="Spring特点"><a href="#Spring特点" class="headerlink" title="Spring特点"></a>Spring特点</h3><blockquote>
<p>它是一个全面的、企业应用开发一站式的解决方案，贯穿表现层、业务层、持久层。但是 Spring仍然可以和其他的框架无缝整合。</p>
</blockquote>
<h3 id="轻量级"><a href="#轻量级" class="headerlink" title="轻量级"></a>轻量级</h3><h3 id="控制反转"><a href="#控制反转" class="headerlink" title="控制反转"></a>控制反转</h3><h3 id="面向切面"><a href="#面向切面" class="headerlink" title="面向切面"></a>面向切面</h3><h3 id="容器"><a href="#容器" class="headerlink" title="容器"></a>容器</h3><h3 id="框架集合"><a href="#框架集合" class="headerlink" title="框架集合"></a>框架集合</h3><p><img src="https://gitee.com/tongstyle/blog-img/raw/master/img/202301201942533.png" srcset="/img/loading.gif" lazyload alt="框架集合"></p>
<h3 id="Spring核心组件"><a href="#Spring核心组件" class="headerlink" title="Spring核心组件"></a>Spring核心组件</h3><p><img src="https://gitee.com/tongstyle/blog-img/raw/master/img/202301201942720.png" srcset="/img/loading.gif" lazyload alt="spring核心组件"></p>
<h3 id="Spring常用模块"><a href="#Spring常用模块" class="headerlink" title="Spring常用模块"></a>Spring常用模块</h3><p><img src="https://gitee.com/tongstyle/blog-img/raw/master/img/202301201942329.png" srcset="/img/loading.gif" lazyload alt="常用模块"></p>
<h3 id="Spring主要包"><a href="#Spring主要包" class="headerlink" title="Spring主要包"></a>Spring主要包</h3><p><img src="https://gitee.com/tongstyle/blog-img/raw/master/img/202301201942662.png" srcset="/img/loading.gif" lazyload alt="主要jar包"></p>
<h3 id="Spring常用注解"><a href="#Spring常用注解" class="headerlink" title="Spring常用注解"></a>Spring常用注解</h3><blockquote>
<p>bean 注入与装配的的方式有很多种，可以通过 xml、get set 方式，、造函数或者注解等。简单易用的方式就是使用 Spring 的注解了，Spring 提供了大量的注解方式  </p>
</blockquote>
<p><img src="https://gitee.com/tongstyle/blog-img/raw/master/img/202301201942615.png" srcset="/img/loading.gif" lazyload alt="spring常用注解"></p>
<h3 id="Spring第三方结合"><a href="#Spring第三方结合" class="headerlink" title="Spring第三方结合"></a>Spring第三方结合</h3><p><img src="https://gitee.com/tongstyle/blog-img/raw/master/img/202301201942195.png" srcset="/img/loading.gif" lazyload alt="第三方框架集成"></p>
<h3 id="Spring-IOC原理"><a href="#Spring-IOC原理" class="headerlink" title="Spring IOC原理"></a>Spring IOC原理</h3><h3 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h3><blockquote>
<p>Spring 通过一个配置文件描述 Bean 及 Bean 之间的依赖关系，利用 Java 语言的反射功能实例化Bean 并建立 Bean 之间的依赖关系。 Spring 的 IoC 容器在完成这些底层工作的基础上，还提供了 Bean 实例缓存、生命周期管理、 Bean 实例代理、事件发布、资源装载等高级服务。</p>
</blockquote>
<h3 id="Spring容器高层视图"><a href="#Spring容器高层视图" class="headerlink" title="Spring容器高层视图"></a>Spring容器高层视图</h3><blockquote>
<p>Spring 启动时读取应用程序提供的 Bean 配置信息，并在 Spring 容器中生成一份相应的 Bean 配置注册表，然后根据这张注册表实例化 Bean，装配好 Bean 之间的依赖关系，为上层应用提供准备就绪的运行环境。其中 Bean 缓存池为 HashMap 实现。</p>
</blockquote>
<h3 id="IOC容器实现"><a href="#IOC容器实现" class="headerlink" title="IOC容器实现"></a>IOC容器实现</h3><h4 id="BeanFactory-框架基础设施"><a href="#BeanFactory-框架基础设施" class="headerlink" title="BeanFactory-框架基础设施"></a>BeanFactory-框架基础设施</h4><blockquote>
<p>BeanFactory 是 Spring 框架的基础设施，面向 Spring 本身；ApplicationContext 面向使用Spring 框架的开发者，几乎所有的应用场合我们都直接使用 ApplicationContext 而非底层的 BeanFactory</p>
</blockquote>
<ol>
<li>BeanDefinitionRegistry 注册表：Spring 配置文件中每一个节点元素在 Spring 容器里都通过一个 BeanDefinition 对象表示，它描述了 Bean 的配置信息。而 BeanDefinitionRegistry 接口提供了向容器手工注册BeanDefinition 对象的方法</li>
<li>BeanFactory 顶层接口：位于类结构树的顶端 ，它最主要的方法就是 getBean(String beanName)，该方法从容器中返回特定名称的 Bean，BeanFactory 的功能通过其他的接口得到不断扩展</li>
<li>ListableBeanFactory：该接口定义了访问容器中 Bean 基本信息的若干方法，如查看 Bean 的个数、获取某一类型Bean 的配置名、查看容器中是否包括某一 Bean 等方法</li>
<li>HierarchicalBeanFactory 父子级联：父子级联 IOC 容器的接口，子容器可以通过接口方法访问父容器； 通过HierarchicalBeanFactory 接口， Spring 的 IOC 容器可以建立父子层级关联的容器体系，子容器可以访问父容器中的 Bean，但父容器不能访问子容器的 Bean。Spring 使用父子容器实现了很多功能，比如在 Spring MVC 中，展现层 Bean 位于一个子容器中，而业务层和持久层的 Bean 位于父容器中。这样，展现层 Bean 就可以引用业务层和持久层的 Bean，而业务层和持久层的 Bean 则看不到展现层的 Bean</li>
<li>ConfigurableBeanFactory：是一个重要的接口，增强了 IoC 容器的可定制性，它定义了设置类装载器、属性编辑器、容器初始化后置处理器等方法</li>
<li>AutowireCapableBeanFactory 自动装配：定义了将容器中的 Bean 按某种规则（如按名字匹配、按类型匹配等）进行自动装配的方法</li>
<li>SingletonBeanRegistry 运行期间注册单例 Bean：定义了允许在运行期间向容器注册单实例 Bean 的方法；对于单实例（ singleton）的 Bean 来说，BeanFactory 会缓存 Bean 实例，所以第二次使用 getBean() 获取 Bean 时将直接从IoC 容器的缓存中获取 Bean 实例。Spring 在 DefaultSingletonBeanRegistry 类中提供了一个用于缓存单实例 Bean 的缓存器，它是一个用 HashMap 实现的缓存器，单实例的 Bean 以beanName 为键保存在这个 HashMap中</li>
<li>依赖日志框架：在初始化 BeanFactory 时，必须为其提供一种日志框架，比如使用 Log4J， 即在类路径下提供 Log4J 配置文件，这样启动 Spring 容器才不会报错</li>
</ol>
<h4 id="ApplicationContext-面向开发应用"><a href="#ApplicationContext-面向开发应用" class="headerlink" title="ApplicationContext 面向开发应用"></a>ApplicationContext 面向开发应用</h4><blockquote>
<p>ApplicationContext由BeanFactory派生而来，提供了更多面向实际应用的功能。ApplicationContext 继承了 HierarchicalBeanFactory 和 ListableBeanFactory 接口，在此基础上，还通过多个其他的接口扩展了 BeanFactory 的功能</p>
</blockquote>
<ol>
<li>ClassPathXmlApplicationContext：默认从类路径加载配置文件</li>
<li>FileSystemXmlApplicationContext：默认从文件系统中装载配置文件</li>
<li>ApplicationEventPublisher：让容器拥有发布应用上下文事件的功能，包括容器启动事件、关闭事件等。</li>
<li>MessageSource：为应用提供 i18n 国际化消息访问的功能；</li>
<li>ResourcePatternResolver ： 所 有 ApplicationContext 实现类都实现了类似于PathMatchingResourcePatternResolver 的功能，可以通过带前缀的 Ant 风格的资源文件路径装载 Spring 的配置文件。</li>
<li>LifeCycle：该接口是 Spring 2.0 加入的，该接口提供了 start()和 stop()两个方法，主要用于控制异步处理过程。在具体使用时，该接口同时被 ApplicationContext 实现及具体Bean 实现，ApplicationContext 会将 start&#x2F;stop 的信息传递给容器中所有实现了该接口的 Bean，以达到管理和控制 JMX、任务调度等目的。</li>
<li>ConfigurableApplicationContext 扩展于 ApplicationContext，它新增加了两个主要的方法： refresh()和 close()，让 ApplicationContext 具有启动、刷新和关闭应用上下文的能力。在应用上下文关闭的情况下调用 refresh()即可启动应用上下文，在已经启动的状态下，调用 refresh()则清除缓存并重新装载配置信息，而调用 close()则可关闭应用上下文</li>
</ol>
<h4 id="WebApplication-体系架构"><a href="#WebApplication-体系架构" class="headerlink" title="WebApplication 体系架构"></a>WebApplication 体系架构</h4><blockquote>
<p>WebApplicationContext 是专门为 Web 应用准备的，它允许从相对于 Web 根目录的路径中装载配置文件完成初始化工作。从 WebApplicationContext 中可以获得ServletContext 的引用，整个 Web 应用上下文对象将作为属性放置到 ServletContext 中，以便 Web 应用环境可以访问 Spring 应用上下文</p>
</blockquote>
<h3 id="SpringBean作用域"><a href="#SpringBean作用域" class="headerlink" title="SpringBean作用域"></a>SpringBean作用域</h3><blockquote>
<p>Spring 3 中为 Bean 定义了 5 中作用域，分别为 singleton（单例）、prototype（原型）、request、session 和 global session，5 种作用域说明如下：</p>
</blockquote>
<ol>
<li><p>singleton：单例模式（多线程下不安全）<br>singleton：单例模式，Spring IoC 容器中只会存在一个共享的 Bean 实例，无论有多少个Bean 引用它，始终指向同一对象。该模式在多线程下是不安全的。Singleton 作用域是Spring 中的缺省作用域，也可以显示的将 Bean 定义为 singleton 模式.<br>配置为：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;userDao&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;com.ioc.UserDaoImpl&quot;</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">&quot;singleton&quot;</span>/&gt;</span><br></code></pre></td></tr></table></figure>

</li>
<li><p>prototype:原型模式每次使用时创建：<br>prototype:原型模式，每次通过 Spring 容器获取 prototype 定义的 bean 时，容器都将创建一个新的 Bean 实例，每个 Bean 实例都有自己的属性和状态，而 singleton 全局只有一个对象。根据经验，对有状态的bean使用prototype作用域，而对无状态的bean使用singleton作用域。</p>
</li>
<li><p>Request：一次 request 一个实例：<br>request：在一次 Http 请求中，容器会返回该 Bean 的同一实例。而对不同的 Http 请求则会产生新的 Bean，而且该 bean 仅在当前 Http Request 内有效,当前 Http 请求结束，该 bean实例也将会被销毁。</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;loginAction&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;com.cnblogs.Login&quot;</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">&quot;request&quot;</span>/&gt;</span><br></code></pre></td></tr></table></figure>

</li>
<li><p>session<br>session：在一次 Http Session 中，容器会返回该 Bean 的同一实例。而对不同的 Session 请求则会创建新的实例，该 bean 实例仅在当前 Session 内有效。同 Http 请求相同，每一次session 请求创建新的实例，而不同的实例之间不共享属性，且实例仅在自己的 session 请求内有效，请求结束，则实例将被销毁。</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;userPreference&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;com.ioc.UserPreference&quot;</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">&quot;session&quot;</span>/&gt;</span><br></code></pre></td></tr></table></figure>

</li>
<li><p>global Session<br>global Session：在一个全局的 Http Session 中，容器会返回该 Bean 的同一个实例，仅在使用 portlet context 时有效。</p>
</li>
</ol>
<h3 id="SpringBean生命周期"><a href="#SpringBean生命周期" class="headerlink" title="SpringBean生命周期"></a>SpringBean生命周期</h3><ol>
<li><blockquote>
<p>实例化<br>实例化一个 Bean，也就是我们常说的 new。</p>
</blockquote>
</li>
<li><blockquote>
<p>IOC 依赖注入<br>按照 Spring 上下文对实例化的 Bean 进行配置，也就是 IOC 注入。</p>
</blockquote>
</li>
<li><blockquote>
<p>setBeanName 实现<br>如果这个 Bean 已经实现了 BeanNameAware 接口，会调用它实现的 setBeanName(String)方法，此处传递的就是 Spring 配置文件中 Bean 的 id 值</p>
</blockquote>
</li>
<li><blockquote>
<p>BeanFactoryAware 实现<br>如果这个 Bean 已经实现了 BeanFactoryAware 接口，会调用它实现的 setBeanFactory，setBeanFactory(BeanFactory)传递的是 Spring 工厂自身（可以用这个方式来获取其它 Bean，只需在 Spring 配置文件中配置一个普通的 Bean 就可以）。</p>
</blockquote>
</li>
<li><blockquote>
<p>ApplicationContextAware 实现<br>如果这个 Bean 已经实现了 ApplicationContextAware 接口，会调用setApplicationContext(ApplicationContext)方法，传入 Spring 上下文（同样这个方式也可以实现步骤 4 的内容，但比 4 更好，因为 ApplicationContext 是 BeanFactory 的子接口，有更多的实现方法）</p>
</blockquote>
</li>
<li><blockquote>
<p>postProcessBeforeInitialization 接口实现-初始化预处理<br>如果这个 Bean 关联了 BeanPostProcessor 接口，将会调用postProcessBeforeInitialization(Object obj, String s)方法，BeanPostProcessor 经常被用作是 Bean 内容的更改，并且由于这个是在 Bean 初始化结束时调用那个的方法，也可以被应用于内存或缓存技术。</p>
</blockquote>
</li>
<li><blockquote>
<p>init-method<br>如果 Bean 在 Spring 配置文件中配置了 init-method 属性会自动调用其配置的初始化方法。</p>
</blockquote>
</li>
<li><blockquote>
<p>postProcessAfterInitialization<br>如果这个 Bean 关联了 BeanPostProcessor 接口，将会调用postProcessAfterInitialization(Object obj, String s)方法。<br>注：以上工作完成以后就可以应用这个 Bean 了，那这个 Bean 是一个 Singleton 的，所以一般情况下我们调用同一个 id 的 Bean 会是在内容地址相同的实例，当然在 Spring 配置文件中也可以配置非 Singleton。</p>
</blockquote>
</li>
<li><blockquote>
<p>Destroy 过期自动清理阶段<br>当 Bean 不再需要时，会经过清理阶段，如果 Bean 实现了 DisposableBean 这个接口，会调用那个其实现的 destroy()方法；</p>
</blockquote>
</li>
<li><blockquote>
<p>destroy-method 自配置清理<br>最后，如果这个 Bean 的 Spring 配置中配置了 destroy-method 属性，会自动调用其配置的销毁方法。</p>
</blockquote>
</li>
</ol>
<pre><code class="hljs">![Bean在Spring Bean应用上下文中的生命周期](https://gitee.com/tongstyle/blog-img/raw/master/img/202301201942515.png)
</code></pre>
<blockquote>
<p> （生命周期）</p>
</blockquote>
<ol start="11">
<li>bean 标签有两个重要的属性（init-method 和 destroy-method）。用它们你可以自己定制初始化和注销方法。它们也有相应的注解（@PostConstruct 和@PreDestroy）。</li>
</ol>
<h3 id="Spring依赖注入四种方式"><a href="#Spring依赖注入四种方式" class="headerlink" title="Spring依赖注入四种方式"></a>Spring依赖注入四种方式</h3><blockquote>
<p><code>构造器注入</code></p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">/*带参数，方便利用构造器进行注入*/</span>   <br><span class="hljs-keyword">public</span> <span class="hljs-title function_">CatDaoImpl</span><span class="hljs-params">(String message)</span>&#123;   <br>    <span class="hljs-built_in">this</span>. message = message;   <br>&#125;<br></code></pre></td></tr></table></figure>

<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;CatDaoImpl&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;com.CatDaoImpl&quot;</span>&gt;</span>   <br>    <span class="hljs-tag">&lt;<span class="hljs-name">constructor-arg</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot; message &quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">constructor-arg</span>&gt;</span>   <br><span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br></code></pre></td></tr></table></figure>

<blockquote>
<p><code>setter 方法注入</code></p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Id</span> &#123;   <br>    <span class="hljs-keyword">private</span> <span class="hljs-type">int</span> id;   <br>    <span class="hljs-keyword">public</span> <span class="hljs-type">int</span> <span class="hljs-title function_">getId</span><span class="hljs-params">()</span> &#123;   <br>        <span class="hljs-keyword">return</span> id;   <br>    &#125;   <br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setId</span><span class="hljs-params">(<span class="hljs-type">int</span> id)</span> &#123;   <br>        <span class="hljs-built_in">this</span>.id = id;   <br>    &#125;   <br>&#125;<br></code></pre></td></tr></table></figure>

<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;id&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;com.id &quot;</span>&gt;</span>   <br>    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;id&quot;</span> <span class="hljs-attr">value</span>=<span class="hljs-string">&quot;123&quot;</span>/&gt;</span>   <br><span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br></code></pre></td></tr></table></figure>

<blockquote>
<p><code>静态工厂注入</code><br>静态工厂顾名思义，就是通过调用静态工厂的方法来获取自己需要的对象，为了让 spring 管理所有对象，我们不能直接通过工程类.静态方法()来获取对象，而是依然通过 spring 注入的形式获取</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">DaoFactory</span> &#123; <span class="hljs-comment">//静态工厂   </span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> FactoryDao <span class="hljs-title function_">getStaticFactoryDaoImpl</span><span class="hljs-params">()</span>&#123;   <br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">StaticFacotryDaoImpl</span>();   <br>    &#125;   <br>&#125;   <br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">SpringAction</span> &#123;   <br>    <span class="hljs-keyword">private</span> FactoryDao staticFactoryDao; <span class="hljs-comment">//注入对象  </span><br>    <span class="hljs-comment">//注入对象的 set 方法   </span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setStaticFactoryDao</span><span class="hljs-params">(FactoryDao staticFactoryDao)</span> &#123;   <br>        <span class="hljs-built_in">this</span>.staticFactoryDao = staticFactoryDao;   <br>    &#125;   <br>&#125;   <br><span class="hljs-comment">//factory-method=&quot;getStaticFactoryDaoImpl&quot;指定调用哪个工厂方法</span><br></code></pre></td></tr></table></figure>

<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;springAction&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot; SpringAction&quot;</span> &gt;</span>   <br>    <span class="hljs-comment">&lt;!--使用静态工厂的方法注入对象,对应下面的配置文件--&gt;</span>   <br>    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;staticFactoryDao&quot;</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">&quot;staticFactoryDao&quot;</span> /&gt;</span>   <br><span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span>   <br><span class="hljs-comment">&lt;!--此处获取对象的方式是从工厂类中获取静态方法--&gt;</span>   <br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;staticFactoryDao&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;DaoFactory&quot;</span> <span class="hljs-attr">factory-method</span>=<span class="hljs-string">&quot;getStaticFactoryDaoImpl&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br></code></pre></td></tr></table></figure>

<blockquote>
<p><code>实例工厂</code><br>实例工厂的意思是获取对象实例的方法不是静态的，所以你需要首先 new 工厂类，再调用普通的实例方法：</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">DaoFactory</span> &#123; <span class="hljs-comment">//实例工厂   </span><br>    <span class="hljs-keyword">public</span> FactoryDao <span class="hljs-title function_">getFactoryDaoImpl</span><span class="hljs-params">()</span>&#123;   <br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">FactoryDaoImpl</span>();   <br>    &#125;   <br>&#125;   <br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">SpringAction</span> &#123;   <br>    <span class="hljs-keyword">private</span> FactoryDao factoryDao; <span class="hljs-comment">//注入对象   </span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">setFactoryDao</span><span class="hljs-params">(FactoryDao factoryDao)</span> &#123;   <br>        <span class="hljs-built_in">this</span>.factoryDao = factoryDao;   <br>    &#125;   <br>&#125;<br></code></pre></td></tr></table></figure>

<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;springAction&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;SpringAction&quot;</span>&gt;</span>   <br>    <span class="hljs-comment">&lt;!--使用实例工厂的方法注入对象,对应下面的配置文件--&gt;</span>   <br>    <span class="hljs-tag">&lt;<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;factoryDao&quot;</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">&quot;factoryDao&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">property</span>&gt;</span>   <br><span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span>   <br><span class="hljs-comment">&lt;!--此处获取对象的方式是从工厂类中获取实例方法--&gt;</span>   <br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;daoFactory&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;com.DaoFactory&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span>   <br><span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;factoryDao&quot;</span> <span class="hljs-attr">factory-bean</span>=<span class="hljs-string">&quot;daoFactory&quot;</span> <span class="hljs-attr">factory-method</span>=<span class="hljs-string">&quot;getFactoryDaoImpl&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">bean</span>&gt;</span><br></code></pre></td></tr></table></figure>

<h3 id="5种不同方式的自动装配"><a href="#5种不同方式的自动装配" class="headerlink" title="5种不同方式的自动装配"></a>5种不同方式的自动装配</h3><blockquote>
<p>Spring 装配包括手动装配和自动装配，手动装配是有基于 xml 装配、构造方法、setter 方法等<br>自动装配有五种自动装配的方式，可以用来指导 Spring 容器用自动装配方式来进行依赖注入。</p>
</blockquote>
<ol>
<li>no：默认的方式是不进行自动装配，通过显式设置 ref 属性来进行装配。</li>
<li>byName：通过参数名 自动装配，Spring 容器在配置文件中发现 bean 的 autowire 属性被设置成 byname，之后容器试图匹配、装配和该 bean 的属性具有相同名字的 bean。</li>
<li>byType：通过参数类型自动装配，Spring 容器在配置文件中发现 bean 的 autowire 属性被设置成 byType，之后容器试图匹配、装配和该 bean 的属性具有相同类型的 bean。如果有多个 bean 符合条件，则抛出错误。</li>
<li>constructor：这个方式类似于 byType， 但是要提供给构造器参数，如果没有确定的带参数的构造器参数类型，将会抛出异常。</li>
<li>autodetect：首先尝试使用 constructor 来自动装配，如果无法工作，则使用 byType 方式。</li>
</ol>
<h3 id="Spring-AOP原理"><a href="#Spring-AOP原理" class="headerlink" title="Spring AOP原理"></a>Spring AOP原理</h3><h3 id="概念-1"><a href="#概念-1" class="headerlink" title="概念"></a>概念</h3><blockquote>
<p>横切的技术，剖解开封装的对象内部，并将那些影响了多个类的公共行为封装到一个可重用模块，并将其命名为Aspect，即切面。所谓切面，简单说就是那些与业务无关，却为业务模块所共同调用的逻辑或责任封装起来，便于减少系统的重复代码，降低模块之间的耦合度，并有利于未来的可操作性和可维护性。<br>使用横切技术，AOP 把软件系统分为两个部分：核心关注点和横切关注点。业务处理的主要流程是核心关注点，与之关系不大的部分是横切关注点。横切关注点的一个特点是，他们经常发生在核心关注点的多处，而各处基本相似，比如权限认证、日志、事物。AOP 的作用在于分离系统中的各种关注点，将核心关注点和横切关注点分离开来。<br>AOP 主要应用场景有：</p>
</blockquote>
<ol>
<li>Authentication 权限</li>
<li>Caching 缓存</li>
<li>Context passing 内容传递</li>
<li>Error handling 错误处理</li>
<li>Lazy loading 懒加载</li>
<li>Debugging 调试</li>
<li>logging, tracing, profiling and monitoring 记录跟踪 优化 校准</li>
<li>Performance optimization 性能优化</li>
<li>Persistence 持久化</li>
<li>Resource pooling 资源池</li>
<li>Synchronization 同步</li>
<li>Transactions 事务</li>
</ol>
<h3 id="AOP核心概念"><a href="#AOP核心概念" class="headerlink" title="AOP核心概念"></a>AOP核心概念</h3><blockquote>
<p>1、切面（aspect）：类是对物体特征的抽象，切面就是对横切关注点的抽象<br>2、横切关注点：对哪些方法进行拦截，拦截后怎么处理，这些关注点称之为横切关注点。<br>3、连接点（joinpoint）：被拦截到的点，因为 Spring 只支持方法类型的连接点，所以在 Spring中连接点指的就是被拦截到的方法，实际上连接点还可以是字段或者构造器。<br>4、切入点（pointcut）：对连接点进行拦截的定义<br>5、通知（advice）：所谓通知指的就是指拦截到连接点之后要执行的代码，通知分为前置、后置、异常、最终、环绕通知五类。<br>6、目标对象：代理的目标对象<br>7、织入（weave）：将切面应用到目标对象并导致代理对象创建的过程<br>8、引入（introduction）：在不修改代码的前提下，引入可以在运行期为类动态地添加一些方法或字段</p>
</blockquote>
<h3 id="AOP两种代理方式"><a href="#AOP两种代理方式" class="headerlink" title="AOP两种代理方式"></a>AOP两种代理方式</h3><blockquote>
<p>Spring 提供了两种方式来生成代理对象: JDKProxy 和 Cglib，具体使用哪种方式生成由AopProxyFactory 根据 AdvisedSupport 对象的配置来决定。默认的策略是如果目标类是接口，则使用 JDK 动态代理技术，否则使用 Cglib 来生成代理<br><code>JDK 动态接口代理</code><br>JDK 动态代理主要涉及到 java.lang.reflect 包中的两个类：Proxy 和 InvocationHandler。InvocationHandler是一个接口，通过实现该接口定义横切逻辑，并通过反射机制调用目标类的代码，动态将横切逻辑和业务逻辑编制在一起。Proxy 利用 InvocationHandler 动态创建一个符合某一接口的实例，生成目标类的代理对象</p>
</blockquote>
<blockquote>
<p><code>CGLib 动态代理</code><br>CGLib 全称为 Code Generation Library，是一个强大的高性能，高质量的代码生成类库，可以在运行期扩展 Java 类与实现 Java 接口，CGLib 封装了 asm，可以在运行期动态生成新的 class。和 JDK 动态代理相比较：JDK 创建代理有一个限制，就是只能为接口创建代理实例，而对于没有通过接口定义业务方法的类，则可以通过 CGLib 创建动态代理。</p>
</blockquote>
<h3 id="实现原理"><a href="#实现原理" class="headerlink" title="实现原理"></a>实现原理</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Aspect</span>  <br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">TransactionDemo</span> &#123;  <br>    <span class="hljs-meta">@Pointcut(value=&quot;execution(* com.example.core.service.*.*.*(..))&quot;)</span>  <br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">point</span><span class="hljs-params">()</span>&#123;  <br>    &#125;  <br>    <span class="hljs-meta">@Before(value=&quot;point()&quot;)</span>  <br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">before</span><span class="hljs-params">()</span>&#123;  <br>        System.out.println(<span class="hljs-string">&quot;transaction begin&quot;</span>);  <br>    &#125;  <br>    <span class="hljs-meta">@AfterReturning(value = &quot;point()&quot;)</span>  <br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">after</span><span class="hljs-params">()</span>&#123;  <br>        System.out.println(<span class="hljs-string">&quot;transaction commit&quot;</span>);  <br>    &#125;  <br>    <span class="hljs-meta">@Around(&quot;point()&quot;)</span>  <br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">around</span><span class="hljs-params">(ProceedingJoinPoint joinPoint)</span> <span class="hljs-keyword">throws</span> Throwable&#123;  <br>        System.out.println(<span class="hljs-string">&quot;transaction begin&quot;</span>);  <br>        joinPoint.proceed();  <br>        System.out.println(<span class="hljs-string">&quot;transaction commit&quot;</span>);  <br>    &#125;  <br>&#125;<br></code></pre></td></tr></table></figure>

<h3 id="SpringMVC原理"><a href="#SpringMVC原理" class="headerlink" title="SpringMVC原理"></a>SpringMVC原理</h3><blockquote>
<p>Spring 的模型-视图-控制器（MVC）框架是围绕一个 DispatcherServlet 来设计的，这个 Servlet会把请求分发给各个处理器，并支持可配置的处理器映射、视图渲染、本地化、时区与主题渲染等，甚至还能支持文件上传。</p>
</blockquote>
<h3 id="MVC流程"><a href="#MVC流程" class="headerlink" title="MVC流程"></a>MVC流程</h3><p><img src="https://gitee.com/tongstyle/blog-img/raw/master/img/202301201942258.png" srcset="/img/loading.gif" lazyload alt="MVC流程"></p>
<blockquote>
<p>Http 请求到 DispatcherServlet</p>
</blockquote>
<ol>
<li>客户端请求提交到 DispatcherServlet</li>
</ol>
<blockquote>
<p>HandlerMapping 寻找处理器<br>2. 由 DispatcherServlet 控制器查询一个或多个 HandlerMapping，找到处理请求的Controller</p>
</blockquote>
<blockquote>
<p>调用处理器 Controller<br>3. DispatcherServlet 将请求提交到 Controller。</p>
</blockquote>
<blockquote>
<p>Controller 调用业务逻辑处理后，返回 ModelAndView<br>4. 调用业务处理和返回结果：Controller 调用业务逻辑处理后，返回 ModelAndView。</p>
</blockquote>
<blockquote>
<p>DispatcherServlet 查询 ModelAndView<br>5. 处理视图映射并返回模型： DispatcherServlet 查询一个或多个 ViewResolver 视图解析器，找到 ModelAndView 指定的视图。</p>
</blockquote>
<blockquote>
<p>ModelAndView 反馈浏览器 HTTP<br>6. Http 响应：视图负责将结果显示到客户端。</p>
</blockquote>
<h3 id="MVC常用注解"><a href="#MVC常用注解" class="headerlink" title="MVC常用注解"></a>MVC常用注解</h3><ol>
<li>@Controller</li>
<li>@RestController</li>
<li>@Component</li>
<li>@Repository</li>
<li>@Service</li>
<li>@ResponseBody</li>
<li>@RequestMapping</li>
<li>@Autowired</li>
<li>@PathVariable</li>
<li>@RequestParam</li>
<li>@RequestHeadler</li>
</ol>
<blockquote>
<p>作用请查看上面 Spring常用注解 图解</p>
</blockquote>
<h3 id="SpringBoot原理"><a href="#SpringBoot原理" class="headerlink" title="SpringBoot原理"></a>SpringBoot原理</h3><blockquote>
<p>Spring Boot 是由 Pivotal 团队提供的全新框架，其设计目的是用来简化新 Spring 应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置，从而使开发人员不再需要定义样板化的配置。通过这种方式，Spring Boot 致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者。其特点如下：</p>
</blockquote>
<ol>
<li>创建独立的 Spring 应用程序</li>
<li>嵌入的 Tomcat，无需部署 WAR 文件</li>
<li>简化 Maven 配置</li>
<li>自动配置 Spring</li>
<li>提供生产就绪型功能，如指标，健康检查和外部配置</li>
<li>绝对没有代码生成和对 XML 没有要求配置</li>
</ol>
<h3 id="JPA原理"><a href="#JPA原理" class="headerlink" title="JPA原理"></a>JPA原理</h3><h3 id="事务"><a href="#事务" class="headerlink" title="事务"></a>事务</h3><blockquote>
<p>事务是计算机应用中不可或缺的组件模型，它保证了用户操作的原子性 ( Atomicity )、一致性( Consistency )、隔离性 ( Isolation ) 和持久性 ( Durabilily)。</p>
</blockquote>
<h3 id="本地事务"><a href="#本地事务" class="headerlink" title="本地事务"></a>本地事务</h3><blockquote>
<p>紧密依赖于底层资源管理器(例如数据库连接)，事务处理局限在当前事务资源内。此种事务处理方式不存在对应用服务器的依赖，因而部署灵活却无法支持多数据源的分布式事务。<br>在数据库连接中使用本地事务示例如下：</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">transferAccount</span><span class="hljs-params">()</span> &#123;   <br>    <span class="hljs-type">Connection</span> <span class="hljs-variable">conn</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;   <br>    <span class="hljs-type">Statement</span> <span class="hljs-variable">stmt</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;   <br>    <span class="hljs-keyword">try</span>&#123;   <br>        conn = getDataSource().getConnection();   <br>        <span class="hljs-comment">// 将自动提交设置为 false，若设置为 true 则数据库将会把每一次数据更新认定为一个事务并自动提交  </span><br>        conn.setAutoCommit(<span class="hljs-literal">false</span>);  <br>        stmt = conn.createStatement();   <br>        <span class="hljs-comment">// 将 A 账户中的金额减少 500  </span><br>        stmt.execute(<span class="hljs-string">&quot;update t_account set amount = amount - 500 where account_id = &#x27;A&#x27;&quot;</span>);  <br>        <span class="hljs-comment">// 将 B 账户中的金额增加 500   </span><br>        stmt.execute(<span class="hljs-string">&quot;update t_account set amount = amount + 500 where account_id = &#x27;B&#x27;&quot;</span>);  <br>        <span class="hljs-comment">// 提交事务  </span><br>        conn.commit();  <br>        <span class="hljs-comment">// 事务提交：转账的两步操作同时成功  </span><br>    &#125; <span class="hljs-keyword">catch</span>(SQLException sqle)&#123;   <br>        <span class="hljs-comment">// 发生异常，回滚在本事务中的操做  </span><br>        conn.rollback();  <br>        <span class="hljs-comment">// 事务回滚：转账的两步操作完全撤销  </span><br>        stmt.close();   <br>        conn.close();   <br>    &#125;   <br>&#125;<br></code></pre></td></tr></table></figure>

<h3 id="分布式事务"><a href="#分布式事务" class="headerlink" title="分布式事务"></a>分布式事务</h3><blockquote>
<p>Java 事务编程接口（JTA：Java Transaction API）和 Java 事务服务 (JTS；Java Transaction Service) 为 J2EE 平台提供了分布式事务服务。分布式事务（Distributed Transaction）包括事务管理器（Transaction Manager）和一个或多个支持 XA 协议的资源管理器 ( Resource Manager )。我们可以将资源管理器看做任意类型的持久化数据存储；事务管理器承担着所有事务参与单元的协调与控制。</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">transferAccount</span><span class="hljs-params">()</span> &#123;   <br>    <span class="hljs-type">UserTransaction</span> <span class="hljs-variable">userTx</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;   <br>    <span class="hljs-type">Connection</span> <span class="hljs-variable">connA</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;   <br>    <span class="hljs-type">Statement</span> <span class="hljs-variable">stmtA</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;   <br>    <span class="hljs-type">Connection</span> <span class="hljs-variable">connB</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;   <br>    <span class="hljs-type">Statement</span> <span class="hljs-variable">stmtB</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;   <br>    <span class="hljs-keyword">try</span>&#123;   <br>        <span class="hljs-comment">// 获得 Transaction 管理对象  </span><br>        userTx = (UserTransaction)getContext().lookup(<span class="hljs-string">&quot;java:comp/UserTransaction&quot;</span>);   <br>        connA = getDataSourceA().getConnection();<span class="hljs-comment">// 从数据库 A 中取得数据库连接  </span><br>        connB = getDataSourceB().getConnection();<span class="hljs-comment">// 从数据库 B 中取得数据库连接  </span><br>        userTx.begin(); <span class="hljs-comment">// 启动事务  </span><br>        stmtA = connA.createStatement();<span class="hljs-comment">// 将 A 账户中的金额减少 500   </span><br>        stmtA.execute(<span class="hljs-string">&quot;update t_account set amount = amount - 500 where account_id = &#x27;A&#x27;&quot;</span>);  <br>        <span class="hljs-comment">// 将 B 账户中的金额增加 500   </span><br>        stmtB = connB.createStatement();   <br>        stmtB.execute(<span class="hljs-string">&quot;update t_account set amount = amount + 500 where account_id = &#x27;B&#x27;&quot;</span>);  <br>        userTx.commit();<span class="hljs-comment">// 提交事务  </span><br>        <span class="hljs-comment">// 事务提交：转账的两步操作同时成功（数据库 A 和数据库 B 中的数据被同时更新）  </span><br>    &#125; <span class="hljs-keyword">catch</span>(SQLException sqle)&#123;   <br>        <span class="hljs-comment">// 发生异常，回滚在本事务中的操纵  </span><br>        userTx.rollback();<span class="hljs-comment">// 事务回滚：数据库 A 和数据库 B 中的数据更新被同时撤销  </span><br>    &#125; <span class="hljs-keyword">catch</span>(Exception ne)&#123;  <br>    &#125;   <br>&#125;<br></code></pre></td></tr></table></figure>

<h3 id="两阶段提交"><a href="#两阶段提交" class="headerlink" title="两阶段提交"></a>两阶段提交</h3><blockquote>
<p>两阶段提交主要保证了分布式事务的原子性：即所有结点要么全做要么全不做，所谓的两个阶段是指：第一阶段：准备阶段；第二阶段：提交阶段。</p>
</blockquote>
<p><img src="https://gitee.com/tongstyle/blog-img/raw/master/img/202301201941273.png" srcset="/img/loading.gif" lazyload alt="两阶段提交"></p>
<blockquote>
<p>1 准备阶段<br>事务协调者(事务管理器)给每个参与者(资源管理器)发送 Prepare 消息，每个参与者要么直接返回失败(如权限验证失败)，要么在本地执行事务，写本地的 redo 和 undo 日志，但不提交，到达一种万事俱备，只欠东风的状态。</p>
</blockquote>
<blockquote>
<p>2 提交阶段<br>如果协调者收到了参与者的失败消息或者超时，直接给每个参与者发送回滚(Rollback)消息；否则，发送提交(Commit)消息；参与者根据协调者的指令执行提交或者回滚操作，释放所有事务处理过程中使用的锁资源。(注意:必须在最后阶段释放锁资源)将提交分成两阶段进行的目的很明确，就是尽可能晚地提交事务，让事务在提交前尽可能地完成所有能完成的工作。</p>
</blockquote>
<h3 id="MyBatis缓存"><a href="#MyBatis缓存" class="headerlink" title="MyBatis缓存"></a>MyBatis缓存</h3><blockquote>
<p>Mybatis 中有一级缓存和二级缓存，默认情况下一级缓存是开启的，而且是不能关闭的。一级缓存是指 SqlSession 级别的缓存，当在同一个 SqlSession 中进行相同的 SQL 语句查询时，第二次以后的查询不会从数据库查询，而是直接从缓存中获取，一级缓存最多缓存 1024 条 SQL。二级缓存是指可以跨 SqlSession 的缓存。是 mapper 级别的缓存，对于 mapper 级别的缓存不同的sqlsession 是可以共享的。</p>
</blockquote>
<p><img src="https://gitee.com/tongstyle/blog-img/raw/master/img/202301201942455.png" srcset="/img/loading.gif" lazyload alt="MyBatis缓存机制"></p>
<h3 id="MyBatis一级缓存原理（sqlsession级别）"><a href="#MyBatis一级缓存原理（sqlsession级别）" class="headerlink" title="MyBatis一级缓存原理（sqlsession级别）"></a>MyBatis一级缓存原理（sqlsession级别）</h3><blockquote>
<p>第一次发出一个查询 sql，sql 查询结果写入 sqlsession 的一级缓存中，缓存使用的数据结构是一个 map。</p>
</blockquote>
<blockquote>
<p>key：MapperID+offset+limit+Sql+所有的入参</p>
</blockquote>
<blockquote>
<p>value：用户信息</p>
</blockquote>
<blockquote>
<p>同一个 sqlsession 再次发出相同的 sql，就从缓存中取出数据。如果两次中间出现 commit 操作（修改、添加、删除），本 sqlsession 中的一级缓存区域全部清空，下次再去缓存中查询不到所以要从数据库查询，从数据库查询到再写入缓存</p>
</blockquote>
<h3 id="二级缓存原理（mapper级别）"><a href="#二级缓存原理（mapper级别）" class="headerlink" title="二级缓存原理（mapper级别）"></a>二级缓存原理（mapper级别）</h3><blockquote>
<p>二级缓存的范围是 mapper 级别（mapper 同一个命名空间），mapper 以命名空间为单位创建缓存数据结构，结构是 map。mybatis 的二级缓存是通过 CacheExecutor 实现的。CacheExecutor其实是 Executor 的代理对象。所有的查询操作，在 CacheExecutor 中都会先匹配缓存中是否存在，不存在则查询数据库。</p>
</blockquote>
<blockquote>
<p>具体使用需要配置：</p>
</blockquote>
<ol>
<li>Mybatis 全局配置中启用二级缓存配置</li>
<li>在对应的 Mapper.xml 中配置 cache 节点</li>
<li>在对应的 select 查询节点中添加 useCache&#x3D;true</li>
</ol>

                
              </div>
            
            <hr/>
            <div>
              <div class="post-metas my-3">
  
    <div class="post-meta mr-3 d-flex align-items-center">
      <i class="iconfont icon-category"></i>
      

<span class="category-chains">
  
  
    
      <span class="category-chain">
        
  <a href="/categories/java%E5%9F%BA%E7%A1%80/" class="category-chain-item">java基础</a>
  
  

      </span>
    
  
</span>

    </div>
  
  
    <div class="post-meta">
      <i class="iconfont icon-tags"></i>
      
        <a href="/tags/java%E5%9F%BA%E7%A1%80/">#java基础</a>
      
    </div>
  
</div>


              
  

  <div class="license-box my-3">
    <div class="license-title">
      <div>spring原理</div>
      <div>http://example.com/2022/12/17/编程语言/Java/学习/基础/004_Spring原理/</div>
    </div>
    <div class="license-meta">
      
        <div class="license-meta-item">
          <div>作者</div>
          <div>深海火锅店</div>
        </div>
      
      
        <div class="license-meta-item license-meta-date">
          <div>发布于</div>
          <div>2022年12月17日</div>
        </div>
      
      
      
        <div class="license-meta-item">
          <div>许可协议</div>
          <div>
            
              
              
                <a target="_blank" href="https://creativecommons.org/licenses/by/4.0/">
                  <span class="hint--top hint--rounded" aria-label="BY - 署名">
                    <i class="iconfont icon-by"></i>
                  </span>
                </a>
              
            
          </div>
        </div>
      
    </div>
    <div class="license-icon iconfont"></div>
  </div>



              
                <div class="post-prevnext my-3">
                  <article class="post-prev col-6">
                    
                    
                      <a href="/2022/12/17/%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/Java/%E5%AD%A6%E4%B9%A0/%E5%9F%BA%E7%A1%80/001_JVM/" title="jvm">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">jvm</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                      <a href="/2022/12/17/%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/Java/%E5%AD%A6%E4%B9%A0/%E5%9F%BA%E7%A1%80/005_Java%E5%9F%BA%E7%A1%80/" title="java基础">
                        <span class="hidden-mobile">java基础</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </article>
                </div>
              
            </div>

            
          </article>
        </div>
      </div>
    </div>

    <div class="side-col d-none d-lg-block col-lg-2">
      
  <aside class="sidebar" style="margin-left: -1rem">
    <div id="toc">
  <p class="toc-header"><i class="iconfont icon-list"></i>&nbsp;目录</p>
  <div class="toc-body" id="toc-body"></div>
</div>



  </aside>


    </div>
  </div>
</div>





  



  



  



  



  







    

    
      <a id="scroll-top-button" aria-label="TOP" href="#" role="button">
        <i class="iconfont icon-arrowup" aria-hidden="true"></i>
      </a>
    

    
      <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v" for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>

    

    
  </main>

  <footer>
    <div class="footer-inner">
  
    <div class="footer-content">
       <a href="https://hexo.io" target="_blank" rel="nofollow noopener"><span>Hexo</span></a> <i class="iconfont icon-love"></i> <a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener"><span>Fluid</span></a> 
    </div>
  
  
    <div class="statistics">
  
  

  
    
      <span id="busuanzi_container_site_pv" style="display: none">
        总访问量 
        <span id="busuanzi_value_site_pv"></span>
         次
      </span>
    
    
      <span id="busuanzi_container_site_uv" style="display: none">
        总访客数 
        <span id="busuanzi_value_site_uv"></span>
         人
      </span>
    
    
  
</div>

  
  
  
</div>

  </footer>

  <!-- Scripts -->
  
  <script  src="https://lib.baomitu.com/nprogress/0.2.0/nprogress.min.js" ></script>
  <link  rel="stylesheet" href="https://lib.baomitu.com/nprogress/0.2.0/nprogress.min.css" />

  <script>
    NProgress.configure({"showSpinner":false,"trickleSpeed":100})
    NProgress.start()
    window.addEventListener('load', function() {
      NProgress.done();
    })
  </script>


<script  src="https://lib.baomitu.com/jquery/3.6.0/jquery.min.js" ></script>
<script  src="https://lib.baomitu.com/twitter-bootstrap/4.6.1/js/bootstrap.min.js" ></script>
<script  src="/js/events.js" ></script>
<script  src="/js/plugins.js" ></script>


  <script  src="https://lib.baomitu.com/typed.js/2.0.12/typed.min.js" ></script>
  <script>
    (function (window, document) {
      var typing = Fluid.plugins.typing;
      var subtitle = document.getElementById('subtitle');
      if (!subtitle || !typing) {
        return;
      }
      var text = subtitle.getAttribute('data-typed-text');
      
        typing(text);
      
    })(window, document);
  </script>




  
    <script  src="/js/img-lazyload.js" ></script>
  




  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/tocbot/4.18.2/tocbot.min.js', function() {
    var toc = jQuery('#toc');
    if (toc.length === 0 || !window.tocbot) { return; }
    var boardCtn = jQuery('#board-ctn');
    var boardTop = boardCtn.offset().top;

    window.tocbot.init(Object.assign({
      tocSelector     : '#toc-body',
      contentSelector : '.markdown-body',
      linkClass       : 'tocbot-link',
      activeLinkClass : 'tocbot-active-link',
      listClass       : 'tocbot-list',
      isCollapsedClass: 'tocbot-is-collapsed',
      collapsibleClass: 'tocbot-is-collapsible',
      scrollSmooth    : true,
      includeTitleTags: true,
      headingsOffset  : -boardTop,
    }, CONFIG.toc));
    if (toc.find('.toc-list-item').length > 0) {
      toc.css('visibility', 'visible');
    }

    Fluid.events.registerRefreshCallback(function() {
      if ('tocbot' in window) {
        tocbot.refresh();
        var toc = jQuery('#toc');
        if (toc.length === 0 || !tocbot) {
          return;
        }
        if (toc.find('.toc-list-item').length > 0) {
          toc.css('visibility', 'visible');
        }
      }
    });
  });
</script>


  <script src=https://lib.baomitu.com/clipboard.js/2.0.11/clipboard.min.js></script>

  <script>Fluid.plugins.codeWidget();</script>


  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/anchor-js/4.3.1/anchor.min.js', function() {
    window.anchors.options = {
      placement: CONFIG.anchorjs.placement,
      visible  : CONFIG.anchorjs.visible
    };
    if (CONFIG.anchorjs.icon) {
      window.anchors.options.icon = CONFIG.anchorjs.icon;
    }
    var el = (CONFIG.anchorjs.element || 'h1,h2,h3,h4,h5,h6').split(',');
    var res = [];
    for (var item of el) {
      res.push('.markdown-body > ' + item.trim());
    }
    if (CONFIG.anchorjs.placement === 'left') {
      window.anchors.options.class = 'anchorjs-link-left';
    }
    window.anchors.add(res.join(', '));

    Fluid.events.registerRefreshCallback(function() {
      if ('anchors' in window) {
        anchors.removeAll();
        var el = (CONFIG.anchorjs.element || 'h1,h2,h3,h4,h5,h6').split(',');
        var res = [];
        for (var item of el) {
          res.push('.markdown-body > ' + item.trim());
        }
        if (CONFIG.anchorjs.placement === 'left') {
          anchors.options.class = 'anchorjs-link-left';
        }
        anchors.add(res.join(', '));
      }
    });
  });
</script>


  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/fancybox/3.5.7/jquery.fancybox.min.js', function() {
    Fluid.plugins.fancyBox();
  });
</script>


  <script>Fluid.plugins.imageCaption();</script>

  <script  src="/js/local-search.js" ></script>

  <script defer src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" ></script>




  
<script src="//cdn.jsdelivr.net/gh/EmoryHuang/BlogBeautify@1.1/DynamicRibbon.min.js"></script>



<!-- 主题的启动项，将它保持在最底部 -->
<!-- the boot of the theme, keep it at the bottom -->
<script  src="/js/boot.js" ></script>


  

  <noscript>
    <div class="noscript-warning">博客在允许 JavaScript 运行的环境下浏览效果更佳</div>
  </noscript>
</body>
</html>
